package org.xpandaframework.base.curd.impl;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.Table;

import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.xpandaframework.base.curd.BaseDao;
import org.xpandaframework.base.exception.BaseDaoException;

/**
 * <p>
 * CopyRright (c)2008-2014: Camelot
 * <p>
 * Project: xpandaframework Maven Webapp
 * <p>
 * Module ID: <模块类编号可以引用系统设计中的类编号>
 * <p>
 * Comments: 持久层实现
 * <p>
 * JDK version used: JDK1.7
 * <p>
 * NameSpace: org.xpandaframework.base.curd.impl.BaseDaoImpl.java
 * <p>
 * Author: Angus
 * <p>
 * Create Date: 2014-11-22
 * <p>
 * Modified By: <修改人中文名或拼音缩写>
 * <p>
 * Modified Date: <修改日期>
 * <p>
 * Why & What is modified: <修改原因描述>
 * <p>
 * Version: v1.0
 */
@Repository("BaseDaoImpl")
public abstract class BaseDaoImpl<T extends BaseEntity> implements BaseDao<T> {

  protected Logger logger = LoggerFactory.getLogger(this.getClass());

  @Autowired(required = true)
  protected SqlSession sqlSessionTemplate;
  // 实体类
  private final Class<T> entityClass;
  // 实体类主键名称
  private String pkName;
  // 实体类ID字段名称
  private String idName;
  // 主键的序列
  private String seq;
  // 数据库表名称
  private String tableName;
  private static final String SQL_CREATE = "create";
  private static final String SQL_UPDATEBYID = "updateById";
  private static final String SQL_READONEBYID = "readOneById";
  private static final String SQL_DELONEBYID = "delOneById";
  /**
   * 作cache 结构{T类的镜像,{数据库列名,实体字段名}}
   */
  private static final Map<Class<?>, Map<String, String>> classFieldMap = new HashMap<Class<?>, Map<String, String>>();
  private Map<String, String> currentColumnFieldNames;
  private final SQLGenerator<T> sqlGenerator;

  @SuppressWarnings("unchecked")
  public BaseDaoImpl() {
    super();
    // 获取EntityClass
    final Type genType = this.getClass().getGenericSuperclass();
    final Type[] params = ((java.lang.reflect.ParameterizedType) genType).getActualTypeArguments();
    this.entityClass = (Class<T>) params[0];
    // 获取所有列名
    this.currentColumnFieldNames = classFieldMap.get(this.entityClass);
    if (null == this.currentColumnFieldNames) {
      this.currentColumnFieldNames = ColumnGenerator.getDBColumn(this.getClass());
      classFieldMap.put(this.entityClass, this.currentColumnFieldNames);
    }
    final Table table = this.entityClass.getAnnotation(Table.class);
    if (null == table) {
      throw new RuntimeException("类-" + this.entityClass + ",未用@Table注解标识!!");
    } else {
      this.tableName = table.name();
    }
    this.sqlGenerator = new SQLGenerator<T>(this.currentColumnFieldNames.keySet(),
        this.tableName, "id", this.seq);
  }

  /*
   * (非 JavaDoc)
   * <p>Title: insert</p>
   * <p>Description: </p>
   * @param t
   * @return
   * @throws BaseDaoException
   * @see org.xpandaframework.base.curd.BaseDao#insert(org.xpandaframework.base.curd.impl.BaseEntity)
   */
  @Override
  public T create(T t) throws BaseDaoException {
    this.sqlSessionTemplate.insert(SQL_CREATE, this.sqlGenerator.sqlInsert(t, this.currentColumnFieldNames));
    return t;
  }

  /*
   * (非 JavaDoc)
   * <p>Title: update</p>
   * <p>Description: </p>
   * @param t
   * @return
   * @throws BaseDaoException
   * @see org.xpandaframework.base.curd.BaseDao#update(org.xpandaframework.base.curd.impl.BaseEntity)
   */
  @Override
  public int updateById(T t) throws BaseDaoException {
    return this.sqlSessionTemplate.update(SQL_UPDATEBYID,
        this.sqlGenerator.sqlUpdateById(t, this.currentColumnFieldNames));
  }

  /*
   * (非 JavaDoc)
   * <p>Title: readOneById</p>
   * <p>Description: </p>
   * @param id
   * @return
   * @throws BaseDaoException
   * @see org.xpandaframework.base.curd.BaseDao#readOneById(java.lang.String)
   */
  @Override
  public T readOneById(Object id) throws BaseDaoException {
    final Map<String, Object> resultMap = this.sqlSessionTemplate.selectOne(SQL_READONEBYID,
        this.sqlGenerator.sqlReadOneById(id));
    return handleResult(resultMap, this.entityClass);
  }

  /*
   * (非 JavaDoc)
   * <p>Title: delOneById</p>
   * <p>Description: </p>
   * @param id
   * @return
   * @throws BaseDaoException
   * @see org.xpandaframework.base.curd.BaseDao#delOneById(java.lang.Object)
   */
  @Override
  public int delOneById(Object id) throws BaseDaoException {
    return this.sqlSessionTemplate.delete(SQL_DELONEBYID, this.sqlGenerator.sqlDelById(id));
  }

  /**
   * 根据resultMap反序列化实体类
   *
   * @param resultMap
   *          结果集
   * @param tClazz
   *          实体类
   * @return T
   * @throws BaseDaoException
   */
  private T handleResult(Map<String, Object> resultMap, Class<T> tClazz) throws BaseDaoException {
    T t = null;
    try {
      t = tClazz.newInstance();
    } catch (final InstantiationException e) {
      this.logger.error("封装查询结果时，实例化对象(" + this.entityClass + ")时，出现异常!" + e.getMessage());
    } catch (final IllegalAccessException e) {
      this.logger.error("封装查询结果时，实例化对象(" + this.entityClass + ")时，出现异常!" + e.getMessage());
    }
    for (final Map.Entry<String, Object> entry : resultMap.entrySet()) {
      String key = entry.getKey();
      key = this.currentColumnFieldNames.get(key);
      final Object val = entry.getValue();
      ReflectionUtils.invokeSetterMethod(t, key, val);
    }
    return t;
  }
  /**************************************************************************************************************/

  // @Override
  // public void create(T t) {
  // this.sqlSessionTemplate.insert("create",
  // this.sqlGenerator.sql_create(t, this.currentColumnFieldNames));
  // }

  // @Override
  // public void createOfBatch(List<T> tList) {
  // if ((null == tList) || tList.isEmpty()) {
  // return;
  // }
  // int len = tList.size(), i = 0;
  // List<T> temp = new ArrayList<T>();
  // // 获取列表的第一个对象的pk的value
  // Object pkVal = null;
  // for (; i < len; i++) {
  // T t = tList.get(i);
  // if (i == 0) {
  // pkVal = ReflectionUtils.invokeGetterMethod(t, this.idName);
  // }
  //
  // temp.add(t);
  // if ((i > 0) && ((i % AssConstant.FLUSH_CRITICAL_VAL) == 0)) {
  // this.sqlSessionTemplateASS.insert("createOfBatch", this.sqlGenerator
  // .sql_createOfBatch(temp, this.currentColumnFieldNames, pkVal));
  // this.sqlSessionTemplateASS.flushStatements();
  // temp = new ArrayList<T>();
  // }
  // }
  // this.sqlSessionTemplateASS.insert("createOfBatch", this.sqlGenerator
  // .sql_createOfBatch(temp, this.currentColumnFieldNames, pkVal));
  // }

  // @Override
  // public void save(T t) {
  // if (StringUtils.isEmpty(this.seq)) {
  // this.create(t);
  // }
  // this.logger.info("生成序列开始:----------start----------");
  // final Long nextval = this.sqlSessionTemplate.selectOne("fetchSeqNextval",
  // "SELECT ".concat(this.seq).concat(" FROM DUAL"));
  // ReflectionUtils.invokeSetterMethod(t, this.idName, nextval);
  // this.logger.info("生成序列结束:---------- end ----------");
  //
  // this.create(t);
  // }

  // @Override
  // public void saveOfBatch(List<T> tList) {
  // if ((null == tList) || tList.isEmpty()) {
  // return;
  // }
  // if (StringUtils.isEmpty(this.seq)) {
  // this.createOfBatch(tList);
  // }
  // this.logger.info("生成序列开始:----------start----------");
  // for (final T t : tList) {
  // final Long nextval = this.sqlSessionTemplate.selectOne("fetchSeqNextval",
  // "SELECT ".concat(this.seq).concat(" FROM DUAL"));
  // ReflectionUtils.invokeSetterMethod(t, this.idName, nextval);
  // }
  // this.logger.info("生成序列结束:---------- end ----------");
  //
  // this.createOfBatch(tList);
  // }

  // @Override
  // public void removeById(PK id) {
  // this.sqlSessionTemplate.delete("removeById",
  // this.sqlGenerator.sql_removeById(id));
  // }

  // @Override
  // public void removeOfBatch(List<PK> ids) {
  // if ((null == ids) || ids.isEmpty()) {
  // return;
  // }
  // int len = ids.size(), i = 0;
  // List<PK> temp = new ArrayList<PK>();
  // for (; i < len; i++) {
  // temp.add(ids.get(i));
  // if ((i > 0) && ((i % AssConstant.FLUSH_CRITICAL_VAL) == 0)) {
  // this.sqlSessionTemplateASS.delete("removeOfBatch",
  // this.sqlGenerator.sql_removeOfBatch(temp));
  // this.sqlSessionTemplateASS.flushStatements();
  // temp = new ArrayList<PK>();
  // }
  // }
  // this.sqlSessionTemplateASS.delete("removeOfBatch",
  // this.sqlGenerator.sql_removeOfBatch(temp));
  // }

  // @Override
  // public void removeAll() {
  // this.sqlSessionTemplate.delete("removeAll",
  // this.sqlGenerator.sql_removeAll());
  // }
  //
  // @Override
  // public void modify(T t) {
  // this.sqlSessionTemplate.update("modify",
  // this.sqlGenerator.sql_modify(t, this.currentColumnFieldNames));
  //
  // }

  // @Override
  // public void modifyOfBatch(List<T> tList) {
  // if ((null == tList) || tList.isEmpty()) {
  // return;
  // }
  // int len = tList.size(), i = 0;
  // for (; i < len; i++) {
  // this.modify(tList.get(i));
  // if ((i > 0) && ((i % AssConstant.FLUSH_CRITICAL_VAL) == 0)) {
  // this.sqlSessionTemplateASS.flushStatements();
  // }
  // }
  // }

  // @Override
  // public T findOneById(PK id) {
  // final Map<String, Object> resultMap = this.sqlSessionTemplate.selectOne(
  // "findOneById", this.sqlGenerator.sql_findOneById(id));
  //
  // return handleResult(resultMap, this.entityClass);
  // }

  /*
   * (非 JavaDoc)
   * <p>Title: findAll</p>
   * <p>Description: </p>
   * @return List<T>
   * @see org.xpandaframework.base.curd.BaseDao#findAll()
   */
  // @Override
  // public List<T> findAll() {
  // final List<Map<String, Object>> resultMapList = this.sqlSessionTemplate.selectList("findAll",
  // this.sqlGenerator.sql_findAll());
  // final List<T> tList = new ArrayList<T>(resultMapList.size());
  // for (final Map<String, Object> resultMap : resultMapList) {
  // final T t = handleResult(resultMap, this.entityClass);
  // tList.add(t);
  // }
  // return tList;
  // }
  //
  // @Override
  // public Long findAllCount() {
  // final Long count = this.sqlSessionTemplate
  // .selectOne("findAllCount", this.sqlGenerator.sql_findAllCount());
  // return count;
  // }
  //

}
